package com.charging.system;

import com.alibaba.fastjson.JSONObject;
import com.charging.common.WePublicUtils;
import com.charging.common.constant.Constants;
import com.charging.common.core.domain.AjaxResult;
import com.charging.common.core.domain.entity.SysUser;
import com.charging.common.utils.SecurityUtils;
import com.charging.common.utils.uuid.UUID;
import com.charging.common.wxpay.WXPayConstants;
import com.charging.common.wxpay.WXPayUtil;
import com.charging.framework.web.service.SysLoginService;
import com.charging.system.domain.*;
import com.charging.system.service.*;
import org.apache.commons.lang3.ObjectUtils;
import org.hibernate.validator.constraints.pl.REGON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 开放接口用于第三方认证和支付类
 *
 */
@RestController
@RequestMapping("/open")
public class OpenController {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private WePublicUtils wePublicUtils;

    @Resource
    private IKxUserInfoService kxUserInfoService;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private SysLoginService loginService;

    @Resource
    private IKxEquipService kxEquipService;

    @Resource
    private IKxRechargeSchemeService kxRechargeSchemeService;

    @Resource
    private IKxRechargeRecordService kxRechargeRecordService;

    private ExecutorService executorService = Executors.newFixedThreadPool(20);


    @GetMapping("/test")
    public AjaxResult test(){
        return AjaxResult.success("测试API可用");
    }

    /**
     * 通过微信code 获取用户的 openid
     * @param code
     * @return
     */
    @GetMapping("/getWePublicCode")
    public AjaxResult getWePublicCode(String code){
        if(wePublicUtils.checkRequestClient() == Constants.TranType.WEIXIN){
            String res = wePublicUtils.getWePublicOpenId(code, Constants.kxSystemInfo.getWxAppId(),Constants.kxSystemInfo.getWxAppSecret());
            JSONObject resJson = JSONObject.parseObject(res);
            if (resJson.containsKey("openid")) {
                String open_id = resJson.getString("openid");
                return AjaxResult.success("ok",open_id);
            }
        }
        return AjaxResult.success("ok","NotGetWePublicCode");
    }

    /**
     * 获取微信签名
     */
    @GetMapping("/getWeSign")
    public AjaxResult getWeSign(String url ){
        return AjaxResult.success("",wePublicUtils.getWeSign(url,Constants.kxSystemInfo.getWxAppId(),Constants.kxSystemInfo.getWxAppSecret()));
    }

    /**
     * 客户端登录验证
     * @param openId
     * @return
     */
    @GetMapping("/welogin")
    public AjaxResult welogin(String openId){
        // 通过openid检查是否存在用户
        KxUserInfo kxUserInfo = new KxUserInfo();
        kxUserInfo.setOpenId(openId);
        kxUserInfo.setUserType(wePublicUtils.checkRequestClient());
        List<KxUserInfo> kxUserInfos =  kxUserInfoService.selectKxUserInfoList(kxUserInfo);
        // 没有账号去注册
        if (kxUserInfos.size()==0 ){
            return  AjaxResult.error("NoOpenId");
        }
        // 多个账号反馈错误
        if (kxUserInfos.size()>1){
            logger.error(openId + " 多账户异常！！！");
            return  AjaxResult.error("您的账号异常请联系：111111");
        }
        kxUserInfo = kxUserInfos.get(0);

        SysUser sysUser = sysUserService.selectUserById(kxUserInfo.getUserId());
        // 检查账号状态
        if ("1".equals(sysUser.getStatus())){
            return  AjaxResult.error("您的账号停用请联系：111111");
        }
        logger.info(sysUser.getUserName() + " 开始登录认证");

        // 生成令牌
        String token = loginService.pubLogin(sysUser.getUserName(), Constants.THIRD_PARTY_CERT_PASSWORD,"",
                "");

        return AjaxResult.success(token);
    }


    /**
     * 创建账号，并绑定第三方openid
     * @return
     */
    @PostMapping("/bindThirdId")
    public AjaxResult bindThirdId(String equipNo,String openId){
        String userName = UUID.getUserNo();
        SysUser checkUserName = new SysUser();
        // 校验自动生成用户名是否存在
        checkUserName.setUserName(userName);
        sysUserService.checkUserNameUnique(checkUserName);
        if(!sysUserService.checkUserNameUnique(checkUserName)){
            logger.info("自动生成号: {} 在系统中,需重新点击",userName);
            return  AjaxResult.error("自动注册失败,请点击[自动注册]按钮");
        }
        //校验 openid 是否存在
        KxUserInfo checkOpenId = new KxUserInfo();
        checkOpenId.setOpenId(openId);
        checkOpenId.setUserType(wePublicUtils.checkRequestClient());
        List<KxUserInfo> kxUserInfos =  kxUserInfoService.selectKxUserInfoList(checkOpenId);
        // 没有账号去注册
        if (kxUserInfos.size()!=0 ){
            logger.error("用户OpenId: {} 重复不能注册",openId);
            return  AjaxResult.error("您已经注册，如不能充电【请重新扫码】");
        }
        // 检查设备是否存在

        KxEquip kxEquip =kxEquipService.getKxEquipByEquipNo(equipNo);
        if(ObjectUtils.isEmpty(kxEquip)){
            return AjaxResult.error("设备编号不正常，请重新选择充电桩");
        }
        // 创建新用户
        SysUser sysUser = new SysUser();
        sysUser.setUserName(userName);
        sysUser.setNickName("充电用户");
        sysUser.setPassword(SecurityUtils.encryptPassword(Constants.THIRD_PARTY_CERT_PASSWORD));
        boolean regFlag = sysUserService.registerUser(sysUser);
        if(!regFlag){
            return AjaxResult.error("注册失败,请联系系统管理人员");
        }

        // 创建用户账户信息
        SysUser newUser = sysUserService.selectUserByUserName(userName);
        KxUserInfo kxUserInfo = new KxUserInfo();
        kxUserInfo.setUserId(newUser.getUserId());
        kxUserInfo.setOpenId(openId);
        kxUserInfo.setUserType(wePublicUtils.checkRequestClient());
        kxUserInfo.setBalance(BigDecimal.ZERO);
        // 检查是否有赠送金额
        KxRechargeScheme kxRechargeScheme = kxRechargeSchemeService.selectKxRechargeSchemeByRechargeSchemeId(kxEquip.getRechargeSchemeId());
        if(ObjectUtils.isNotEmpty(kxRechargeScheme)&&kxRechargeScheme.getRegisterGive().compareTo(BigDecimal.ZERO)==1){
            KxRechargeRecord kxRechargeRecord = new KxRechargeRecord();
            kxRechargeRecord.setUserId(newUser.getUserId());
            kxRechargeRecord.setTranType(Constants.TranType.NOKNOW);
            kxRechargeRecord.setTranStatus(Constants.TranStatus.YES);
            kxRechargeRecord.setRechargeSchemeId(kxRechargeScheme.getRechargeSchemeId());
            kxRechargeRecord.setBalance(BigDecimal.ZERO);
            kxRechargeRecord.setGive(kxRechargeScheme.getRegisterGive());
            kxRechargeRecordService.insertKxRechargeRecord(kxRechargeRecord);
            kxUserInfo.setGive(kxRechargeScheme.getRegisterGive());
        }
        kxUserInfoService.insertKxUserInfo(kxUserInfo);
        return AjaxResult.success("注册成功");
    }

    /**
     * 微信支付结果回调
     * https://www.jb51.net/article/218723.htm
     * @return
     */
    @PostMapping(value = "/wx/notify")
    public void notify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            String notityXml = sb.toString();

            logger.info("[微信支付回调] 接收微信回调,结果:{}",notityXml);
            Map<String, String> notityMap = WXPayUtil.xmlToMap(notityXml);
            if("SUCCESS".equals(notityMap.get("return_code"))){
                String sing = WXPayUtil.generateSignature(notityMap, Constants.kxSystemInfo.getWxPayKey(), WXPayConstants.SignType.MD5);
                if(sing.equals(notityMap.get("sign"))){
                    // 使用线程处理账户信息
                    executorService.execute(new Runnable() {
                        @Override
                        public void run() {
                            //返回信息
                            //拿到结果判断金额,修改状态
                            // payService.handleNotify(result);
                            KxRechargeRecord kxRechargeRecord = kxRechargeRecordService.selectKxRechargeRecordByRechargeRecordId(Long.valueOf(notityMap.get("out_trade_no").replace(Constants.PAY_SIGN,"")));
                            if(kxRechargeRecord.getTranStatus() == Constants.TranStatus.NO){// 交易状态是未交易时使用
                                kxRechargeRecordService.rechargeSuccessAction(kxRechargeRecord);
                                logger.info("[微信支付回调] 微信支付回调订单：{}处理成功",notityMap.get("out_trade_no"));
                            }else {
                                logger.info("[微信支付回调] 微信支付回调订单：{}订单已经处理",notityMap.get("out_trade_no"));
                            }
                        }
                    });

                    logger.error("[微信支付回调] 接收微信回调: 反馈微信解析成功，进行系统业务处理过程");
                    BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                    out.write(WXPayConstants.WX_PAY_NOTIFY_SUCCESS_XML.getBytes());
                    out.flush();
                    out.close();
                }else {
                    logger.error("[微信支付回调] 接收微信回调业务处理失败:sign Error");
                }
            }else {
                logger.error("[微信支付回调] 接收微信回调业务处理失败:return_code Error");
            }

        }catch (Exception e){
            e.printStackTrace();
            logger.error("[微信支付回调] 接收微信回调,错误：{}", e.getMessage());
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(WXPayConstants.WX_PAY_NOTIFY_ERROR_XML.getBytes());
            out.flush();
            out.close();
        }
    }

}
